<template>
  <div v-loading="loading">
    <BasicForm @register="registerForm" v-show="formConfig">
      <template #[item]="{ model, field }" v-for="item in data.slots">
        <slot :name="item" v-bind="model[field]"></slot>
      </template>
      <template #[item]="data" v-for="item in Object.keys($slots)">
        <slot :name="item" v-bind="data || {}"></slot>
      </template>
    </BasicForm>
    <Empty v-if="!formConfig" description="尚未配置表单"></Empty>
  </div>
</template>
<script lang="ts" setup name="render-page">
  import { ref, watch, onMounted, unref, nextTick, defineAsyncComponent, PropType } from "vue";
  import { useMessage } from "/@/hooks/web/useMessage"
  import type { DynamicProps } from "/#/utils"
  import { useComponentRegister } from "/@/components/Form/index"
  import * as diyFormApi from "/@/api/infra/diyForm"
  import { useAttrs } from "/@/hooks/core/useAttrs"
  import { BasicForm, useForm, FormSchema, FormActionType, FormProps } from "/@/components/Form/index"
  import { doMapperField } from "./fieldMapper"
  import { Empty } from "ant-design-vue"

  const { createMessage } = useMessage()
  type Props = Partial<DynamicProps<FormProps>>
  const emit = defineEmits(["register", "success"])
  const attrs = useAttrs({ excludeDefaultKeys: false })
  const loading = ref(false)
  const isInit = ref(false)
  const lastFormValues = ref<any>({})
  const formSchemas = ref<any[]>([])
  useComponentRegister(
    "MyAlert",
    defineAsyncComponent(() => import(`/@/components/My/MyAlert.vue`))
  )

  /**
   * 表单配置和表单id二选1
   */
  const props = defineProps({
    // 表单配置
    config: { type: Object, required: false },
    // 表单id
    formId: { type: String, required: false },
    // diy字段名称, 如果指定了, 在获取表单字段时候会使用当前字段作为一个对象, 所有diy字段会被放到该对象中
    diyFieldName: { type: String, required: false },
    // 前置表单信息
    beforeFormSchema: { type: Array as PropType<FormSchema[]>, default: [] },
    // 后置表单信息
    afterFormSchema: { type: Array as PropType<FormSchema[]>, default: [] },
  })
  const formConfig = ref()
  const data = ref<any>({
    slots: [],
  })

  const [registerForm, { resetFields, setFieldsValue, resetSchema, setProps, validate }]: [any, FormActionType] = useForm({
    showActionButtonGroup: false
  })

  const setValues = async (values: Object) => {
    const { diyFieldName } = props
    const formValues = { ...values }
    if (!diyFieldName) {
      await setFieldsValue(formValues)
      return
    }

    const diyFormValues = formValues[`${diyFieldName}`]
    delete formValues[`${diyFieldName}`]
    for (const key in diyFormValues) {
      formValues[`${diyFieldName}_${key}`] = diyFormValues[key];
    }
    console.log('newFormValue', formValues)
    lastFormValues.value = { ...lastFormValues.value, ...formValues }
    await setFieldsValue(formValues)
  }

  const getValues = async () => {
    const { diyFieldName } = props
    const values = await validate() || {}
    const formValues = { ...values }

    const excludeComponents = ['Divider']

    formSchemas.value.forEach((item) => {
      if (excludeComponents.includes(item.component)) {
        delete formValues[item.field]
      }
    })

    if (!diyFieldName) {
      return formValues
    }

    // 创建一个 diyFieldValues 对象，用于存放 custom@ 字段
    const diyFieldValues = {};

    // 遍历原对象的字段
    for (const key in formValues) {
      if (key.startsWith(diyFieldName + '_')) {
        // 去掉前缀，放入 diyFieldValues
        const newKey = key.replace(diyFieldName + '_', '');
        diyFieldValues[newKey] = formValues[key];
        // 针对多选优化
        if (diyFieldValues[newKey] && diyFieldValues[newKey].includes(',')) {
          diyFieldValues[newKey] = diyFieldValues[newKey].split(',').map(item => item.trim());
        }
        // 删除原对象中的该字段
        delete formValues[key];
      }
    }

    // 将 diyFieldValues 对象添加到原对象中
    formValues[`${diyFieldName}`] = diyFieldValues;
    console.log(`${diyFieldName}`, diyFieldValues)
    return formValues
  }

  /**
   * 添加固定表单元素并排序
   * @param diyFormSchemas
   */
  const getFormSchemas = (diyFormSchemas : any[]) => {
 
    const diyFormIdSchema = {
      label: "",
      field: props.diyFieldName ? `${props.diyFieldName}_diyFormId` : 'diyFormId',
      component: "Input",
      show: false
    }
    return [ ...props.beforeFormSchema, diyFormIdSchema, ...diyFormSchemas, ...props.afterFormSchema ]
  }

  const renderForm = () => {
    const { globalConfig, widgetList } = doMapperField(formConfig.value || {})
    if (isInit.value) {
      console.info("表单已初始化过")
      return
    }
    nextTick(async () => {
      const formProps = {
        labelCol: {
          md: { span: 4 },
          sm: { span: 6 },
        },
        wrapperCol: { lg: 24, md: 24 },
        showActionButtonGroup: false,
        ...globalConfig,
      }
      await setProps(formProps)

      const formSchema = widgetList.map((e) => {
        const { formItemFlag, useAsFormItem } = e.formItem || {}
        let slot = null
        if (!useAsFormItem && formItemFlag) {
          slot = e.formItem.field
          data.value.slots.push(slot)
        }
        const fieldKey = props.diyFieldName ? `${props.diyFieldName}_${e.formItem.field}` : e.formItem.field
        return {
          slot,
          ...e.formItem,
          field: fieldKey,
          useFormItemWrapper: e.formItem?.useAsFormItem,
          componentProps: { ...e.props },
        }
      })

      const newFormSchemas = getFormSchemas(formSchema)
      await resetSchema(newFormSchemas)
      isInit.value = true

      if (lastFormValues.value) {
        console.log('lastFormValues', unref(lastFormValues))
        await setFieldsValue(unref(lastFormValues))
        lastFormValues.value = {}
      }
      console.log("formSchema", newFormSchemas)
      formSchemas.value = newFormSchemas
      await setProps({ schemas: newFormSchemas })
    })
  }

  watch(
    () => props.formId,
    async (formId: String) => {
      if (!formId) {
        return
      }
      console.log('diyFormId', formId)
      loading.value = true
      try {
        const data = await diyFormApi.getDiyForm({ id: formId })
        if (!data?.formConfig) {
          return 
        }
        formConfig.value = data?.formConfig
      } finally {
        loading.value = false
      }
    }, { immediate: true }
  )

  watch(
    () => props.config,
    (val: Object) => {
      if (!val) {
        return
      }
      formConfig.value = val
    }, { immediate: true, deep: true }
  )

  watch(
    () => formConfig.value,
    (config: Object) => {
      if (!config) {
        return
      }
      renderForm()
    }
  )

  defineExpose({
    getValues,
    setValues,
    getForm: () => {
      return {
        setFieldsValue,
        resetFields,
        setProps
      }
    }
  })
</script>
